<template>
  <view class="execution-maze">
    <div class="execution-maze__control">
      <g-select
        v-model="mazeSize"
        title="游戏难度"
        :options="levelOptions"
        @change="setGameLevel"
      />
      <g-timer />
      <g-help name="execution_maze">
        <div>{{ ins }}</div>
        <view class="table">
          <view class="tr" style="height:70rpx">
            <view class="td">当前</view>
            <view class="td">移动</view>
            <view class="td">返回</view>
          </view>
          <view class="tr" style="height:70rpx">
            <view class="td currentColor" />
            <view class="td moveColor" />
            <view class="td badColor" />
          </view>
        </view>
      </g-help>
    </div>

    <view class="mapZone">
      <view class="map-wrap">
        <view id="map" class="map-container">
          <block v-for="item in outMaze" :key="item.tr">
            <view class="tr" :style="{height:cellHeight}">
              <block v-for="td in item.td" :key="td.id">
                <view :id="td.id" :class="td.class" />
              </block>
            </view>
          </block>
        </view>
        <img class="icon-exit" src="./icon-exit.png">
      </view>
    </view>

    <ControlGroup @click="move" />

    <fixed-bottom text="生成迷宫">
      <GameButtonGroup :max="levelCount" :current="gameLevel" :played="played" @replay="startGame" @pre="pre" @next="next" />
    </fixed-bottom>
  </view>
</template>

<script>
import GTimer from '@/components/GTimer.vue'
import GHelp from '@/components/GHelp.vue'
import GSelect from '@/components/GSelect.vue'
import FixedBottom from '@/components/FixedBottom/index.vue'
import Taro from '@tarojs/taro'
import GameButtonGroup from '@/components/GameButtonGroup.vue'
import GameMixin from '@/mixins/GameMixin'
import ControlGroup from './components/ControlGroup.vue'

export default {
  components: {
    GTimer,
    GHelp,
    GSelect,
    FixedBottom,
    GameButtonGroup,
    ControlGroup
  },
  mixins: [GameMixin],
  data() {
    return {
      mazeSize: 4,
      levelOptions: [
        { name: '入门', value: 4 },
        { name: '进阶', value: 6 },
        { name: '中级', value: 8 },
        { name: '高级', value: 10 }
      ],
      cellHeight: '70rpx',
      updateLog: '2019/09/04 新建页面（页面迷宫固定，demo做成）\n2019/09/05 页面迷宫动态生成（微信效率高，秒出）\n2019/09/06 添加自动寻路功能（网页效率高，秒出）',
      ins: '将黄色方块移动到右下角出口, 上下左右按钮控制方块移动方向',
      showTag: '#CAEACE',
      outMaze: [
        { tr: 1, td: [
          { id: 'c1', class: 'td hleft hbottom moveColor currentColor' },
          { id: 'c2', class: 'td hbottom hright' },
          { id: 'c3', class: 'td hleft hright' },
          { id: 'c4', class: 'td hleft hbottom hright' },
          { id: 'c5', class: 'td hleft hright' },
          { id: 'c6', class: 'td hleft hbottom' },
          { id: 'c7', class: 'td hright' },
          { id: 'c8', class: 'td hbottom hleft hright' },
          { id: 'c9', class: 'td hleft hright' },
          { id: 'c10', class: 'td hleft' }] },
        { tr: 2, td: [
          { id: 'c11', class: 'td htop hbottom' },
          { id: 'c12', class: 'td hbottom htop hright' },
          { id: 'c13', class: 'td hleft' },
          { id: 'c14', class: 'td htop hright' },
          { id: 'c15', class: 'td hleft' },
          { id: 'c16', class: 'td htop' },
          { id: 'c17', class: 'td hright' },
          { id: 'c18', class: 'td hright hleft htop' },
          { id: 'c19', class: 'td hbottom hleft hright' },
          { id: 'c20', class: 'td hleft hbottom' }] },
        { tr: 3, td: [
          { id: 'c21', class: 'td htop hright' },
          { id: 'c22', class: 'td hleft htop hright' },
          { id: 'c23', class: 'td hleft hbottom' },
          { id: 'c24', class: 'td hright' },
          { id: 'c25', class: 'td hbottom hleft' },
          { id: 'c26', class: 'td hright' },
          { id: 'c27', class: 'td hbottom hleft' },
          { id: 'c28', class: 'td hbottom' },
          { id: 'c29', class: 'td hbottom htop' },
          { id: 'c30', class: 'td htop hbottom' }] },
        { tr: 4, td: [
          { id: 'c31', class: 'td hbottom' },
          { id: 'c32', class: 'td hbottom' },
          { id: 'c33', class: 'td htop hright hbottom' },
          { id: 'c34', class: 'td hleft hright hbottom' },
          { id: 'c35', class: 'td hleft htop' },
          { id: 'c36', class: 'td hbottom' },
          { id: 'c37', class: 'td hright htop' },
          { id: 'c38', class: 'td hbottom htop hleft' },
          { id: 'c39', class: 'td hbottom htop' },
          { id: 'c40', class: 'td htop' }] },
        { tr: 5, td: [
          { id: 'c41', class: 'td hright htop' },
          { id: 'c42', class: 'td hbottom htop hleft' },
          { id: 'c43', class: 'td htop' },
          { id: 'c44', class: 'td htop hright' },
          { id: 'c45', class: 'td hleft hbottom' },
          { id: 'c46', class: 'td hright htop hbottom' },
          { id: 'c47', class: 'td hright hleft' },
          { id: 'c48', class: 'td hbottom hleft htop hright' },
          { id: 'c49', class: 'td hleft htop' },
          { id: 'c50', class: 'td hbottom' }] },
        { tr: 6, td: [
          { id: 'c51', class: 'td hright' },
          { id: 'c52', class: 'td hright hleft htop' },
          { id: 'c53', class: 'td hright hleft' },
          { id: 'c54', class: 'td hright hbottom hleft' },
          { id: 'c55', class: 'td htop hleft' },
          { id: 'c56', class: 'td htop' },
          { id: 'c57', class: 'td hright' },
          { id: 'c58', class: 'td hright htop hleft' },
          { id: 'c59', class: 'td hright hleft' },
          { id: 'c60', class: 'td hbottom hleft htop' }] },
        { tr: 7, td: [
          { id: 'c61', class: 'td hright' },
          { id: 'c62', class: 'td hright hbottom hleft' },
          { id: 'c63', class: 'td hright hbottom hleft' },
          { id: 'c64', class: 'td htop hleft hright hbottom' },
          { id: 'c65', class: 'td hleft' },
          { id: 'c66', class: 'td hright hbottom' },
          { id: 'c67', class: 'td hbottom hleft hright' },
          { id: 'c68', class: 'td hleft' },
          { id: 'c69', class: 'td hright hbottom' },
          { id: 'c70', class: 'td hbottom htop hleft' }] },
        { tr: 8, td: [
          { id: 'c71', class: 'td hright hbottom' },
          { id: 'c72', class: 'td htop hleft' },
          { id: 'c73', class: 'td htop hbottom' },
          { id: 'c74', class: 'td htop' },
          { id: 'c75', class: 'td hright' },
          { id: 'c76', class: 'td htop hleft' },
          { id: 'c77', class: 'td hbottom htop hright' },
          { id: 'c78', class: 'td hleft hbottom' },
          { id: 'c79', class: 'td htop' },
          { id: 'c80', class: 'td hbottom htop' }] },
        { tr: 9, td: [
          { id: 'c81', class: 'td htop hright' },
          { id: 'c82', class: 'td hleft' },
          { id: 'c83', class: 'td htop hright' },
          { id: 'c84', class: 'td hleft hright' },
          { id: 'c85', class: 'td hleft hright hbottom' },
          { id: 'c86', class: 'td hleft hright' },
          { id: 'c87', class: 'td hleft htop' },
          { id: 'c88', class: 'td htop hright' },
          { id: 'c89', class: 'td hleft hright hbottom' },
          { id: 'c90', class: 'td hleft hbottom htop' }] },
        { tr: 10, td: [
          { id: 'c91', class: 'td hright' },
          { id: 'c92', class: 'td hright hleft' },
          { id: 'c93', class: 'td hright hleft' },
          { id: 'c94', class: 'td hright hleft' },
          { id: 'c95', class: 'td htop hleft hright' },
          { id: 'c96', class: 'td hleft hright' },
          { id: 'c97', class: 'td hleft hright' },
          { id: 'c98', class: 'td hleft' },
          { id: 'c99', class: 'td htop' },
          { id: 'c100', class: 'td hright htop' }] }
      ],
      globalData: {
        id: 1,
        n: 10,
        isClear: false
      },
      played: false
    }
  },
  created() {
    this.startGame()
  },
  methods: {
    onGameLevelChange(level) {
      this.mazeSize = this.levelOptions[level].value
    },
    move(direction) {
      this.played = true
      var isClear = this.globalData.isClear
      if (isClear) return // 通关终止 *新加
      var n = this.globalData.n
      let idaf = null
      switch (direction) {
        case 'top':
          idaf = this.globalData.id - n
          break
        case 'right':
          idaf = this.globalData.id + 1
          break
        case 'left':
          idaf = this.globalData.id - 1
          break
        default:
          idaf = this.globalData.id + n
          break
      }
      this.globalData.id = this.doMoveDecision(this.globalData.id, direction, idaf)
      // isCommandPhone(39);
      if (!isClear && this.globalData.id === n * n) {
        this.globalData.isClear = true
        // alert("恭喜你获得了胜利 🎉🎉。Congratulations!");
        Taro.showModal({
          content: '恭喜你获得了胜利 🎉🎉',
          showCancel: false
        })
      }
    },
    /**
   * 滑动开始
   */
    mytouchstart: function mytouchstart(evt) {
      if (this.globalData.isClear) return // 通关终止 *新加
      var touch = evt.touches[0]
      this.globalData.touchStartX = parseInt(touch.pageX)
      this.globalData.touchStartY = parseInt(touch.pageY)
    },
    /**
   * 滑动中
   */
    mytouchmove: function mytouchmove(evt) {
      if (this.globalData.isClear) return // 通关终止 *新加
      var touch = evt.touches[0]
      this.globalData.touchEndX = parseInt(touch.pageX)
      this.globalData.touchEndY = parseInt(touch.pageY)
    },
    /**
   * 滑动结束
   */
    mytouchend: function mytouchend(evt) {
      var isClear = this.globalData.isClear
      if (isClear) return // 通关终止 *新加
      var touchMoveX = this.globalData.touchEndX - this.globalData.touchStartX
      var touchMoveY = this.globalData.touchEndY - this.globalData.touchStartY
      var n = this.globalData.n
      var TOP = 'top'
      var BOTTOM = 'bottom'
      var LEFT = 'left'
      var RIGHT = 'right'

      if (Math.abs(touchMoveX) < Math.abs(touchMoveY) && touchMoveY < -30) {
        this.globalData.id = this.doMoveDecision(this.globalData.id, TOP, this.globalData.id - n)
      // isCommandPhone(38);
      } else if (Math.abs(touchMoveY) < Math.abs(touchMoveX) && touchMoveX > 30) {
        this.globalData.id = this.doMoveDecision(this.globalData.id, RIGHT, this.globalData.id + 1)
        // isCommandPhone(39);
        if (!isClear && this.globalData.id === n * n) {
          this.globalData.isClear = true
          // alert("恭喜你获得了胜利 🎉🎉。Congratulations!");
          Taro.showModal({
            content: '恭喜你获得了胜利 🎉🎉',
            showCancel: false
          })
        }
      } else if (Math.abs(touchMoveY) < Math.abs(touchMoveX) && touchMoveX < -30) {
        this.globalData.id = this.doMoveDecision(this.globalData.id, LEFT, this.globalData.id - 1)
      // isCommandPhone(37);
      } else if (Math.abs(touchMoveX) < Math.abs(touchMoveY) && touchMoveY > 30) {
        this.globalData.id = this.doMoveDecision(this.globalData.id, BOTTOM, this.globalData.id + n)
        // isCommandPhone(40);
        if (!isClear && this.globalData.id === n * n) {
          this.globalData.isClear = true
          // alert("恭喜你获得了胜利 🎉🎉。Congratulations!");
          Taro.showModal({
            content: '恭喜你获得了胜利 🎉🎉',
            showCancel: false
          })
        }
      }
    },
    // スタイルを変更する。
    doMoveDecision: function(idbf, direction, idaf) {
      var n = this.globalData.n
      if (!(idaf >= 1 && idaf <= n * n)) return idbf // 错误位置终止 *新加

      var rowIndexBf = idbf % n === 0 ? idbf / n - 1 : parseInt(idbf / n)
      var classIndexBf = idbf % n === 0 ? n - 1 : idbf - 1 - (parseInt(idbf / n) * n)
      var rowIndexAf = idaf % n === 0 ? idaf / n - 1 : parseInt(idaf / n)
      var classIndexAf = idaf % n === 0 ? n - 1 : idaf - 1 - (parseInt(idaf / n) * n)
      // 限界の場合、処理しない
      if ((idbf === 1 && direction === 'left') || idbf === n * n) {
        return idbf
      }

      if (this.outMaze[rowIndexBf].td[classIndexBf].class.indexOf('h' + direction) > 0) {
        if (this.outMaze[rowIndexAf].td[classIndexAf].class.indexOf('moveColor') > 0) {
          this.outMaze[rowIndexBf].td[classIndexBf].class = this.outMaze[rowIndexBf].td[classIndexBf].class.replace(/moveColor/g, '') + ' badColor'
        }
        this.outMaze[rowIndexAf].td[classIndexAf].class = this.outMaze[rowIndexAf].td[classIndexAf].class.replace(/badColor/g, '') + ' moveColor'

        // 現在場所変更
        this.outMaze[rowIndexBf].td[classIndexBf].class = this.outMaze[rowIndexBf].td[classIndexBf].class.replace(/currentColor/g, '')
        this.outMaze[rowIndexAf].td[classIndexAf].class = this.outMaze[rowIndexAf].td[classIndexAf].class + ' currentColor'

        return idaf
      }
      return idbf
    },
    bindKeyInput: function(e) {
      this.mazeSize = e.detail.value
    },
    // 判断
    doCheck: function() {
      var tempSize = Number(this.mazeSize)
      if (isNaN(tempSize) || tempSize < 2 || tempSize > 70) {
        wx.showToast({
          title: '错误范围(2-70)',
          icon: 'none',
          duration: 2000
        })
        return false
      }
      return true
    },
    // 迷路生成開始
    startGame: function() {
      if (!this.doCheck()) {
        return
      }

      // パラメータを初期化する
      this.globalData.id = 1
      this.globalData.n = Number(this.mazeSize)
      this.globalData.isClear = false
      var n = this.globalData.n
      // bug修改：调整宽度后无法复原的问题
      this.cellHeight = '70rpx'

      var x = 1
      var xn = 1
      var rotes = new Array(n * n)
      var roteSize = 1
      var map = this.createMazes(n)
      while (roteSize < n * n) {
        var op = Math.floor(Math.random() * 4) + 1
        xn = this.doNext(op, x, n)
        if (xn === x) {
          continue
        } else if (rotes[xn - 1] === '*') {
          x = xn
        } else {
          map = this.createRotes(map, x, xn, op)
          x = xn
          rotes[x - 1] = '*'
          roteSize++
        }
      }

      this.heightReset()
      this.outMaze = map
    },
    // 迷路地図を初期化する。
    createMazes: function(length) {
      var map = []
      var no = 1
      for (var xline = 1; xline <= length; xline++) {
        var tr = { tr: xline, td: [] }
        for (var yline = 1; yline <= length; yline++) {
          var td = { id: no, class: 'td' }
          tr.td.push(td)
          no++
        }
        map.push(tr)
      }
      map[0].td[0].class = 'td hleft'
      map[length - 1].td[length - 1].class = 'td hright'
      return map
    },
    // 迷路の道を作る。
    createRotes: function(map, point, pointNx, op) {
    // 現在の座標にクラスを追加する。
      var clsStr = this.getClass(op)
      if (point === 1) {
        clsStr = clsStr + ' moveColor currentColor'
      }
      var n = this.globalData.n
      var rowIndex = point % n === 0 ? point / n - 1 : parseInt(point / n)
      var classIndex = point % n === 0 ? n - 1 : point - 1 - (parseInt(point / n) * n)
      map[rowIndex].td[classIndex].class = map[rowIndex].td[classIndex].class + ' ' + clsStr

      // 次の座標にクラスを追加する。
      var clsStrNx = this.getClassAf(op)
      rowIndex = pointNx % n === 0 ? pointNx / n - 1 : parseInt(pointNx / n)
      classIndex = pointNx % n === 0 ? n - 1 : pointNx - 1 - (parseInt(pointNx / n) * n)
      map[rowIndex].td[classIndex].class = map[rowIndex].td[classIndex].class + ' ' + clsStrNx

      return map
    },
    // 次の座標を取得する
    doNext: function(rnd, x, n) {
      switch (rnd) {
        // 上
        case 1: {
          if (this.isNotIllegal(x - n, n)) {
            x = x - n
          }
          break
        }
        // 右
        case 2: {
          if (x % n !== 0 && this.isNotIllegal(x + 1, n)) {
            x = x + 1
          }
          break
        }
        // 左
        case 3: {
          if (x % n !== 1 && this.isNotIllegal(x - 1, n)) {
            x = x - 1
          }
          break
        }
        // 下
        case 4: {
          if (this.isNotIllegal(x + n, n)) {
            x = x + n
          }
          break
        }
      }
      return x
    },
    // 座標の正しさを判断する
    isNotIllegal: function(x, n) {
      if (x > 1 && x <= n * n) {
        return true
      } else {
        return false
      }
    },
    // HTMLClassを取得する
    getClass: function(operation) {
      var clsStr = ''
      switch (operation) {
        case 1: {
          clsStr = 'htop'
          break
        }
        case 2: {
          clsStr = 'hright'
          break
        }
        case 3: {
          clsStr = 'hleft'
          break
        }
        case 4: {
          clsStr = 'hbottom'
          break
        }
      }
      return clsStr
    },
    // 後HTMLClassを取得する
    getClassAf: function(operation) {
      var clsStr = ''
      switch (operation) {
        case 1: {
          clsStr = 'hbottom'
          break
        }
        case 2: {
          clsStr = 'hleft'
          break
        }
        case 3: {
          clsStr = 'hright'
          break
        }
        case 4: {
          clsStr = 'htop'
          break
        }
      }
      return clsStr
    },
    // 高さをリセットする。
    heightReset: function() {
      // var winWid = wx.getSystemInfoSync().windowWidth / this.globalData.n
      // // スクリーンの幅は迷路より小さい時
      // if (winWid < 80) {
      //   this.cellHeight = winWid + 'rpx'
      // }
      this.cellHeight = '70rpx'
    },
    // 迷路を自動的にクリアする。
    autoClear: function() {
      if (this.globalData.isClear) return // 通关终止 *新加
      var n = this.globalData.n
      // 「→ ↓ ↑ ←」の方向通り、重複なルートが一切ない、効率が高い。
      var rootStack = []
      rootStack.push(this.globalData.id)
      var rootOps = [2, 4, 1, 3]
      var clearRoots = new Array(n * n)
      var nextId
      var rootDirection
      while (this.globalData.id !== n * n) {
        for (var opInx in rootOps) {
          nextId = this.doNext(rootOps[opInx], this.globalData.id, n)
          // 移動できない場合
          if (this.globalData.id === nextId) {
            if (opInx === 3) {
            // 通り抜けられない道は、前の道を戻る。
              rootStack.pop()
              this.globalData.id = rootStack[rootStack.length - 1]
            }
            continue
          }

          switch (rootOps[opInx]) {
            case 1: {
              rootDirection = 'top'
              break
            }
            case 2: {
              rootDirection = 'right'
              break
            }
            case 3: {
              rootDirection = 'left'
              break
            }
            case 4: {
              rootDirection = 'bottom'
              break
            }
          }

          var rowIndex = this.globalData.id % n === 0 ? this.globalData.id / n - 1 : parseInt(this.globalData.id / n)
          var classIndex = this.globalData.id % n === 0 ? n - 1 : this.globalData.id - 1 - (parseInt(this.globalData.id / n) * n)
          this.outMaze[rowIndex].td[classIndex].class.indexOf('h' + rootDirection)
          // 通路、探した道判断
          if (this.outMaze[rowIndex].td[classIndex].class.indexOf('h' + rootDirection) < 0 || clearRoots[nextId - 1] === 'C') {
            if (opInx === 3) {
            // 通り抜けられない道は、前の道を戻る。
              rootStack.pop()
              this.globalData.id = rootStack[rootStack.length - 1]
            }
            continue
          } else {
            clearRoots[nextId - 1] = 'C'
            rootStack.push(nextId)
            this.globalData.id = nextId
            break
          }
        }
      }
      let rowIndexRoot
      let classIndexRoot
      // 路線を描く
      for (var inx in rootStack) {
        var rootId = rootStack[inx]

        rowIndexRoot = rootId % n === 0 ? rootId / n - 1 : parseInt(rootId / n)
        classIndexRoot = rootId % n === 0 ? n - 1 : rootId - 1 - (parseInt(rootId / n) * n)

        if (inx === 0) {
          this.outMaze[rowIndexRoot].td[classIndexRoot].class = this.outMaze[rowIndexRoot].td[classIndexRoot].class.replace(/currentColor/g, '')
          continue
        }
        if (this.outMaze[rowIndexRoot].td[classIndexRoot].class.indexOf('moveColor') > 0) {
          var rowIndexRootBf = rootStack[inx - 1] % n === 0 ? rootStack[inx - 1] / n - 1 : parseInt(rootStack[inx - 1] / n)
          var classIndexRootBf = rootStack[inx - 1] % n === 0 ? n - 1 : rootStack[inx - 1] - 1 - (parseInt(rootStack[inx - 1] / n) * n)
          console.log(rowIndexRootBf, classIndexRootBf, '=====')
          this.outMaze[rowIndexRootBf].td[classIndexRootBf].class = this.outMaze[rowIndexRootBf].td[classIndexRootBf].class.replace(/moveColor/g, '') + ' badColor'
        }
        this.outMaze[rowIndexRoot].td[classIndexRoot].class = this.outMaze[rowIndexRoot].td[classIndexRoot].class.replace(/badColor/g, '') + ' moveColor'
      }
      this.outMaze[rowIndexRoot].td[classIndexRoot].class = this.outMaze[n - 1].td[n - 1].class + ' currentColor'

      this.globalData.isClear = true
      Taro.showModal({
        content: '恭喜你获得了胜利 🎉🎉',
        showCancel: false
      })
    }
  }
}
</script>

<style lang="less">
@import './index.less';
</style>
